#include "render/scene3D.h"
#include "render/render_system.h"
#include <opengl/opengl_shader.h>
#include "entity/point_entity.h"
#include "entity/line_entity.h"
#include "entity/triangle_entity.h"
#include "entity/sprite.h"
#include "entity/cube.h"
#include "entity/panel.h"
#include "entity/camera.h"

namespace engine
{
    Cube *cube1;
    Panel *panel1;
    // Cube *cube2;
    // Cube *cube3;
    // Texture2D *texture2d;
    // PointEntity *point1;
    // LineEntity *line1;
    // TriangleEntity *tri;
    // TriangleEntity *tri2;
    // Sprite *sprite;

    Scene3D::Scene3D()
    {
        this->shader = RenderSystem::getInstance()->loadShader("world3d", "./assets/shader/world3D.vs", "./assets/shader/world3D.fs", NULL);
        this->objectRoot = new Object3D(); // 场景根对象

        this->camera = new Camera(); // 新建相机
        this->camera->setPosition(0.0f, 10.0f, 10.0f);
        this->camera->setRotate(-45, 0, 0);

        // 投影矩阵
        this->shader->use();
        shader->setMatrix4("projection", glm::perspective(glm::radians(45.0f), (float)800 / (float)600, 0.1f, 100.0f));

        RenderSystem::getInstance()->loadTexture("container", "./assets/texture/container.jpg", GL_FALSE);
        RenderSystem::getInstance()->loadTexture("wood", "./assets/texture/wood.png", GL_FALSE);
        RenderSystem::getInstance()->loadTexture("null", "./assets/texture/wood1.png", GL_FALSE);

        cube1 = new Cube("cube1", this->shader, RenderSystem::getInstance()->getTexture("container"));
        cube1->setPosition(0, 0, 0);
        cube1->setColor(1, 1, 1);
        // cube1->setScale(10.0f, 10.0f, 10.0f);

        panel1 = new Panel("panel1", this->shader, RenderSystem::getInstance()->getTexture("wood"));
        panel1->setPosition(0.0f, -1.0f, 0.0f);
        panel1->setScale(10.0f, 10.0f, 10.0f);

        this->objectRoot->addChildren(panel1);
        this->objectRoot->addChildren(cube1);

        glEnable(GL_DEPTH_TEST);

        ENGINE_INFO("Scene3D Created");
    }

    Scene3D::~Scene3D()
    {
        Shader *shader = RenderSystem::getInstance()->getShader("world3d");
        RenderSystem::getInstance()->removeShader("world3d");
        delete shader;
        Texture2D *texture = RenderSystem::getInstance()->getTexture("wood");
        RenderSystem::getInstance()->removeTexture("wood");
        delete texture;
    }

    void Scene3D::render(double time)
    {
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        // 视口矩阵
        this->shader->use();
        shader->setMatrix4("view", this->camera->getViewMatrix());
        // use lights
        // setupLights(_lights);
        // texture

        // vertex&index
        //  point1->drawVertex();
        //  line1->drawVertex();
        //  line1->drawVertex();
        for (int i = 0; i < this->objectRoot->mChildren.size(); i++)
        {
            ((Entity3D *)(objectRoot->mChildren[i]))->render();
        }

        // cube1->render();
        // panel1->render();
        // sprite->move();
        // shader->setMatrix4("transform", sprite->getTransformMatrix());
        // sprite->drawIndex();
        // shader->setMatrix4("model", cube1->getTransformMatrix());
        // cube1->drawVertex();
        // shader->setMatrix4("model", cube2->getTransformMatrix());
        // cube2->drawVertex();
        // tri->drawVertex();
        // glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
        // glDrawArrays(GL_TRIANGLES, 0, 3);
        // glBindVertexArray(0); // no need to unbind it every time
    }
    // 处理输入
    void Scene3D::processInput(GLFWwindow *window)
    {
        if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
            glfwSetWindowShouldClose(window, true);

        float cameraSpeed = 0.1f; // adjust accordingly
        if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
            camera->move(0, 0, -cameraSpeed);
        if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
            camera->move(0, 0, cameraSpeed);
        if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
            camera->move(-cameraSpeed, 0, 0);
        if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
            camera->move(cameraSpeed, 0, 0);
    }
}